package com.demarc.pesquisas.web.jsf;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;

import org.omnifaces.util.Components;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;

import com.demarc.pesquisas.infraestrutura.persistencia.Filtro;
import com.demarc.pesquisas.infraestrutura.persistencia.ResultadoPaginado;

@SuppressWarnings("serial")
public abstract class ListaDataModel<T extends Serializable> extends
		LazyDataModel<T> {

	protected Filtro ultimoFiltro;
	protected Filtro filtro;
	private boolean jaConsultado;

	/**
	 * Constrói um objeto ListaDataModel
	 * 
	 * @param filtro
	 *            Objeto Filtro que será utilizado nas consultas
	 */
	public ListaDataModel(Filtro filtro) {
		this.filtro = filtro;
		this.jaConsultado = true;
	}

	/**
	 * Constrói um objeto ListaDataModel
	 * 
	 * @param filtro
	 *            Objeto Filtro que será utilizado nas consultas
	 * @param jaConsultado
	 *            Objeto que define se a pesquisa deve ser executada assim que
	 *            esta classe for instanciada.
	 */
	public ListaDataModel(Filtro filtro, boolean jaConsultado) {
		this(filtro);
		this.jaConsultado = jaConsultado;
	}

	/**
	 * Reseta o conteúdo da dataModel
	 */
	protected void resetTable() {
		UIComponent component = Components.getCurrentComponent();
		if (component instanceof DataTable) {
			((DataTable) component).reset();
		}
	}

	/**
	 * Executa a pesquisa
	 */
	@Override
	public final List<T> load(int first, int pageSize, String sortField,
			SortOrder sortOrder, Map<String, String> filters) {

		List<T> retorno = new ArrayList<T>();

		filtro.setPrimeiroElemento(first);
		filtro.setQuantidadeMaximaResultados(pageSize);
		if (sortField != null) {
			filtro.getOrdem().clear();
			filtro.adicionarOrdem(sortField,
					SortOrder.ASCENDING.equals(sortOrder));
		}

		ResultadoPaginado<T> resultado = new ResultadoPaginado<T>(
				new ArrayList<T>(), 0);
		if (jaConsultado) {
			resultado = consultarPorFiltro();
		}

		setRowCount(resultado.getRowCount());
		resetTable();
		ultimoFiltro = new Filtro(filtro);
		retorno = resultado.getList();

		return retorno;
	}

	@Override
	public Object getRowKey(T object) {
		return ((List<T>) getWrappedData()).indexOf(object);
	}

	@Override
	public void setRowIndex(int rowIndex) { // NOPMD
		if (getPageSize() == 0) {
			rowIndex = -1;
		}
		super.setRowIndex(rowIndex);
	}

	@Override
	public T getRowData(String rowKey) {
		int index = Integer.valueOf(rowKey);
		if (index >= 0) {
			return ((List<T>) getWrappedData()).get(index);
		}
		return null;
	}

	public final List<T> carregarTodosPorFiltro() {
		ultimoFiltro.setPrimeiroElemento(0);
		ultimoFiltro.setQuantidadeMaximaResultados(Integer.MAX_VALUE);

		ResultadoPaginado<T> resultado = new ResultadoPaginado<T>(
				new ArrayList<T>(), 0);
		if (jaConsultado) {
			resultado = consultarPorUltimoFiltro(ultimoFiltro);
		}
		setRowCount(resultado.getRowCount());

		return resultado.getList();
	}

	public boolean isJaConsultado() {
		return jaConsultado;
	}

	public void setJaConsultado(boolean jaConsultado) {
		this.jaConsultado = jaConsultado;
	}

	protected abstract ResultadoPaginado<T> consultarPorFiltro();

	protected abstract ResultadoPaginado<T> consultarPorUltimoFiltro(
			Filtro ultimoFiltro);
}
